﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VideoReflector.Models;

namespace VideoReflector.Controllers
{
    /// <summary>
    /// Selects sub-sets of a list of clip tag based on specified sets of conditions
    /// </summary>
    public class ClipTagFilter
    {
        #region Private fields

        private IList<int> _clipTagGroupIds;
        private IList<int> _participantIds;
        private IList<string> _noteKeywords;
        private bool _sort;

        #endregion // Private fields

        #region Constructors

        /// <summary>
        /// Clip tag list filter constructor
        /// </summary>
        /// <param name="cliptagGroupIds"> List of tag group IDs to filter by </param>
        /// <param name="participantIds"> List of participant IDs to filter by </param>
        /// <param name="sort"> Whether to sort the filtered output by the tag timestamps or maintain original order </param>
        /// <param name="notesKeywords"> Optional list of keywords to check for in tag notes as filter </param>
        /// /// <param name="sort"> Whether to sort the returned list by the clip tag start times </param>
        public ClipTagFilter(IList<int> cliptagGroupIds, IList<int> participantIds, IList<string> notesKeywords = null, bool sort = false)
        {
            _clipTagGroupIds = cliptagGroupIds;
            _participantIds = participantIds;
            _noteKeywords = notesKeywords;
            _sort = sort;
        }

        /// <summary>
        /// Clip tag list filter constructor
        /// </summary>
        /// <param name="clipTagGroups"> List of clip tag groups to filter by </param>
        /// <param name="participants"> List of session participants to filter by </param>
        /// <param name="notesKeywords"> Optional list of keywords to check for in tag notes as filter </param>
        /// <param name="sort"> Whether to sort the returned list by the clip tag start times </param>
        public ClipTagFilter(IList<ClipTagGroup> clipTagGroups, IList<Participant> participants, IList<string> notesKeywords = null, bool sort = false)
        {
            _clipTagGroupIds = (from tagGroup in clipTagGroups select tagGroup.ID).ToList();
            _participantIds = (from participant in participants select participant.ID).ToList();
            _noteKeywords = notesKeywords;
            _sort = sort;     
        }

        #endregion // Constructors

        #region Public methods

        /// <summary>
        /// Apply the filter conditions to the supplied list of clip tags
        /// </summary>
        /// <param name="sourceTags"> List of clip tags to filter </param>
        /// <returns> List of clip tags meeting filter conditions </returns>
        public IList<ClipTag> Filter(IList<ClipTag> sourceTags)
        {
            // apply filter to specified tag list, optionally executing a sub-query if note keyword filter specified
            // to select only tags where notes contain at least one of specified keywords
            var filteredTagsQuery = from tag in sourceTags
                                    where _clipTagGroupIds.Contains(tag.GroupID) && _participantIds.Contains(tag.Originator)
                                          && (
                                                (_noteKeywords != null && _noteKeywords.Count != 0)
                                                    ? tag.Notes != null 
                                                            ? (from word in tag.Notes.Split(' ') 
                                                               where _noteKeywords.Contains(word) 
                                                               select word).Count() > 0 
                                                            : false
                                                    : true
                                             )
                                    select tag;
            // order by timestamps if sort flag set
            if (_sort) { filteredTagsQuery = filteredTagsQuery.OrderBy(tag => tag.StartTime); }
            // evaluate query and return list
            return filteredTagsQuery.ToList();
        }

        #endregion // Public methods
    }
}
